package main

import (
	"camp_lucky_draw/entity"
	"encoding/json"
	"fmt"
	"math"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"sync"
)

/**
* @author aFun
* @data 2025/4/16 19:50
* @email: afunaaa222@163.com / 1030935903
* @address: Guangdong University of Technology, China
 */

func cmd_test() {
	for i := 0; i < 10; i++ {
		roleID := strconv.Itoa(i)
		cmd := exec.Command("./tttt.exe", "-role_id", roleID)
		output, err := cmd.CombinedOutput()
		if err != nil {
			fmt.Println("Error:", err)
		}
		fmt.Println(string(output))
	}
}

var RmMutex sync.Mutex = sync.Mutex{}

func main() {
	dir := "./auto_client_logger"
	// 检查目录是否存在
	if _, err := os.Stat(dir); err == nil {
		// 存在则删除
		err := os.RemoveAll(dir)
		if err != nil {
			fmt.Println("删除目录失败:", err)
			return
		}
		fmt.Println("已删除目录:", dir)
	} else if !os.IsNotExist(err) {
		fmt.Println("检查目录失败:", err)
		return
	}

	// 创建新的空目录
	err := os.MkdirAll(dir, os.ModePerm)
	if err != nil {
		fmt.Println("创建目录失败:", err)
		return
	}
	fmt.Println("已创建目录:", dir)

	// 用 sync.WaitGroup 管理 goroutine   取代掉 select{}， 不然退出会报错哦~虽然没什么影响，但是就是难看
	var wg sync.WaitGroup
	ExecNum := 500
	var RmMP = make(map[int]*entity.ReportMetrics, ExecNum)
	for i := 1; i <= ExecNum; i++ {
		wg.Add(1)
		go func(roleID int) {
			defer wg.Done()
			cmd := exec.Command("./auto_client.exe", "-role_id", strconv.Itoa(roleID))
			output, err := cmd.CombinedOutput()
			if err != nil {
				fmt.Println("Error:", err)
			}
			rm := &entity.ReportMetrics{}
			err = json.Unmarshal(output, rm)
			if err != nil {
				fmt.Println("Error:", err)
			}
			RmMutex.Lock()
			RmMP[roleID] = rm
			RmMutex.Unlock()
		}(i)
	}
	wg.Wait()
	collectMetrics(RmMP)
}

func collectMetrics(mp map[int]*entity.ReportMetrics) {
	var QPSList, AvgList, P99List []float64
	totalSuccess := int64(0)
	totalFail := int64(0)
	totalCount := int64(0)
	for _, m := range mp {
		QPSList = append(QPSList, m.QPS)
		AvgList = append(AvgList, m.Avg)
		P99List = append(P99List, m.P99)
		totalSuccess += m.Success
		totalFail += m.Fail
		totalCount++
	}

	successRate := float64(totalSuccess) / float64(totalSuccess+totalFail) * 100
	failRate := float64(totalFail) / float64(totalSuccess+totalFail) * 100

	fmt.Println("QPS    -> Mean:", mean(QPSList), ", Median:", median(QPSList), ", Mode:", mode(QPSList))
	fmt.Println("Avg    -> Mean:", mean(AvgList), ", Median:", median(AvgList), ", Mode:", mode(AvgList))
	fmt.Println("P99    -> Mean:", mean(P99List), ", Median:", median(P99List), ", Mode:", mode(P99List))
	fmt.Println("成功总数:", totalSuccess)
	fmt.Println("失败总数:", totalFail)
	fmt.Printf("成功率: %.2f%%\n", successRate)
	fmt.Printf("失败率: %.2f%%\n", failRate)
}

func mean(values []float64) float64 {
	sum := 0.0
	for _, v := range values {
		sum += v
	}
	return sum / float64(len(values))
}

func median(values []float64) float64 {
	sort.Float64s(values)
	n := len(values)
	if n%2 == 0 {
		return (values[n/2-1] + values[n/2]) / 2
	}
	return values[n/2]
}

func mode(values []float64) float64 {
	freq := make(map[float64]int)
	maxFreq := 0
	mode := math.NaN()
	for _, v := range values {
		freq[v]++
		if freq[v] > maxFreq {
			maxFreq = freq[v]
			mode = v
		}
	}
	return mode
}
